package yz_service

import (
	"encoding/json"
	"fmt"
	"math/rand"
	"peilian-api/app/global/common"
	"peilian-api/app/global/databases/tables"
	"peilian-api/app/global/log"
	"peilian-api/app/global/variable"
	"peilian-api/app/services/user_service"
	"peilian-api/utils/tools"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
)

type Bs struct{}

// 创建订单
func createTradeInfo(ctx *gin.Context, mr ParamBaseReq) error {
	// 获取订单的详细信息
	msg := tools.UrlDecode(mr.Msg)
	var msgInfo MsgInfoCreate
	err := json.Unmarshal([]byte(msg), &msgInfo)
	if err != nil {
		fmt.Println(err)
		return err
	}

	var bid = mr.Id // 交易id
	// 查询订单是否存在
	trade, exists, _ := new(tables.YzTrade).GetTradeInfoByBid(bid)
	// 无论该交易存不存在，都要创建商品
	var idStr []uint
	for i := 0; i < len(msgInfo.Foi.OrdersDetail); i++ {
		var items tables.YzItems
		items.Bid = mr.Id
		items.Oid = msgInfo.Foi.OrdersDetail[i].Oid
		items.ItemId = msgInfo.Foi.OrdersDetail[i].ItemId
		items.Num = msgInfo.Foi.OrdersDetail[i].Num
		items.Title = msgInfo.Foi.OrdersDetail[i].Title
		items.Price = msgInfo.Foi.OrdersDetail[i].Price
		items.Alais = msgInfo.Foi.OrdersDetail[i].Alias
		id := new(tables.YzItems).CreateItems(items)
		if id == 0 {
			continue
		}
		idStr = append(idStr, id)
	}
	b, _ := json.Marshal(idStr)
	if exists { // 该交易已经存在
		if trade.Status == tables.TradeSuccess || trade.Status == tables.TradeClose || trade.Status == tables.TradePaid {
			// 该交易已经存在，无需进行更新
			return nil
		}
		trade.DeletedAt = gorm.DeletedAt{time.Now(), true}
		new(tables.YzTrade).UpdateTrade(trade.ID, trade, "deleted_at") // 将原来的订单，删除掉
	}

	// 解密手机号码
	token, err := new(YzApi).GetAccessTokenApi(ctx)
	if err != nil {
		return err
	}
	phone, err := new(YzApi).DecryptSingle(ctx, msgInfo.Foi.BuyerInfo.BuyerPhone, token)
	if err != nil {
		return err
	}

	// 交易不存在, 创建该交易
	var t tables.YzTrade
	t.MsgId = mr.MsgId
	t.Bid = bid
	t.YzOpenId = msgInfo.Foi.BuyerInfo.YzOpenId
	t.BuyerPhone = msgInfo.Foi.BuyerInfo.BuyerPhone
	t.BuyerRealPhone = phone
	t.OuterUserId = msgInfo.Foi.BuyerInfo.OuterUserId
	t.Status = msgInfo.Foi.OrderInfoDetail.Status
	t.CreateTradeTime = msgInfo.Foi.OrderInfoDetail.Created
	t.ItemIds = string(b)
	err = new(tables.YzTrade).CreateTrade(t)
	return err
}

// 交易支付
func successTradeInfo(ctx *gin.Context, mr ParamBaseReq) error {
	// 获取订单的详细信息
	msg := tools.UrlDecode(mr.Msg)
	var msgInfo MsgInfoPay
	err := json.Unmarshal([]byte(msg), &msgInfo)
	if err != nil {
		return err
	}
	var bid = mr.Id // 交易id
	// 1. 查询订单是否存在
	trade, exists, _ := new(tables.YzTrade).GetTradeInfoByBid(bid)
	if exists && trade.Status == tables.TradeWaitBuyerPay { // 创建完成，需要支付
		trade.Status = tables.TradePaid // 订单支付成功
		trade.PayFinishTradeTime = msgInfo.Foi.OrderInfoDetail.PayTime
		selectField := []string{"status", "pay_finish_trade_time"}
		err := new(tables.YzTrade).UpdateTrade(trade.ID, trade, selectField...) // 更新关闭消息
		if err != nil {
			return fmt.Errorf("该交易状态更新失败")
		}
	} else {
		// 订单不存在
		return fmt.Errorf("该交易订单还不存在，请手动处理")
	}

	// 2. 根据手机号查询游客信息
	phone := trade.BuyerRealPhone
	if phone == "" {
		return fmt.Errorf("该用户不存在，手机号：%s", phone)
	}
	u, exists, err := tables.GetAnonymousInfoByPhone(phone)
	if err != nil {
		return fmt.Errorf("该用户查询失败，手机号：%s", phone)
	}
	if !exists {
		// 创建一个游客用户，并返回用户信息
		var user = tables.User{
			Phone:      phone,
			Type:       tables.UserTypeAnonymous,
			Name:       fmt.Sprintf("用户%s%d", fmt.Sprintf("%03v", rand.New(rand.NewSource(time.Now().UnixNano())).Int31n(1000)), time.Now().Unix()%1670000000),
			TrailCount: uint(common.DefaultUserTrailCount), // 游客默认面试次数
		}
		dc := variable.DB.MySQL.Create(&user)
		if err := dc.Error; err != nil {
			return fmt.Errorf("该用户自动创建失败，手机号：%s", phone)
		}
		u = user // 将创建的用户，赋值给u
		log.Logger.InfoMsgF(ctx, fmt.Sprintf("手机号为[%s]的用户购买会员,并为其自动创建账户, uid:%d", phone, u.ID))
	}

	var ids []int
	json.Unmarshal([]byte(trade.ItemIds), &ids)
	// 3. 获取该订单的商品信息
	items := new(tables.YzItems).GetItems(ids)
	if len(items) == 0 {
		return fmt.Errorf("该商品不存在，交易id:%s", bid)
	}
	// 4. 获取会员计算标准
	cc, _ := new(tables.CommonConf).FetchByConfKey(tables.ConfKeyMember)
	if len(cc) == 0 {
		return fmt.Errorf("无资费标准，请联系管理员添加, 交易id:%s", bid)
	}
	var memberMoney = make(map[string]int, 0)
	json.Unmarshal([]byte(cc[0].ConfValue), &memberMoney)
	// 5. 计算会员到期时间
	var memberTitle = ""
	var expireDayNums = 0 // 天数
	for i := 0; i < len(items); i++ {
		memberTitle = memberTitle + items[i].Title + ","
		expireDayNums = expireDayNums + items[i].Num*memberMoney[items[i].Title]
	}
	// 6. 从购买日期开始计算 过期时间
	var startDate = trade.PayFinishTradeTime
	duetimecst, _ := time.ParseInLocation("2006-01-02 15:04:05", startDate, time.Local)
	t := duetimecst.Add(time.Hour * 24 * time.Duration(expireDayNums))
	dateTime := t.Format("2006-01-02")
	expireTime := dateTime + " 23:59:59"
	// 7. 插入会员信息 & 会员卡未到期，继续购买会员卡
	// 查询该交易的订单是否存在
	member, exists, err := new(tables.Member).GetMemberInfoByUid(int64(u.ID))
	if err != nil {
		return fmt.Errorf("交易信息查询失败")
	}
	if !exists {
		id := new(tables.Member).CreateMember(tables.Member{Uid: int64(u.ID), Bid: trade.Bid, Title: strings.Trim(memberTitle, ","), Phone: trade.BuyerRealPhone, MemberStartTime: trade.PayFinishTradeTime, MemberExpire: expireTime})
		if id == 0 {
			return fmt.Errorf("会员信息创建失败")
		}
	} else if member.Bid != bid { // 如果会员不存在，新的会员
		// 删除原来的交易单
		err = new(tables.Member).DeleteMemberInfoById(int64(member.ID))
		if err != nil {
			return fmt.Errorf("会员信息删除失败")
		}
		// 判断会员是否到期
		diff, _ := tools.GetDaysBetween2Date("2006-01-02 15:04:05", member.MemberExpire, time.Now().UTC().Format("2006-01-02 15:04:05"))
		if diff > 0 { // 会员未到期
			// 在过期的基础上，重新计算过期日期
			duetimecst, _ := time.ParseInLocation("2006-01-02 15:04:05", member.MemberExpire, time.Local)
			t := duetimecst.Add(time.Hour * 24 * time.Duration(expireDayNums))
			dateTime := t.Format("2006-01-02")
			expireTime = dateTime + " 23:59:59"

		}
		// 重新添加会员
		id := new(tables.Member).CreateMember(tables.Member{Uid: int64(u.ID), Bid: trade.Bid, Title: strings.Trim(memberTitle, ","), Phone: trade.BuyerRealPhone, MemberStartTime: trade.PayFinishTradeTime, MemberExpire: expireTime})
		if id == 0 {
			return fmt.Errorf("会员信息创建失败")
		}
	}

	// 8. 更新用户会员生效表
	u.IsMember = tables.MemberStatusHas // 会员生效
	daySum, _ := tools.GetDaysBetween2Date("2006-01-02 15:04:05", expireTime, time.Now().UTC().Format("2006-01-02 15:04:05"))
	if daySum == 0 {
		u.IsMember = tables.MemberStatusExpire // 置为过期状态
	}
	_, err = tables.UpdateUserInfoById(u, int(u.ID), []string{"is_member"})
	if err != nil {
		return fmt.Errorf("会员生效状态更新失败")
	}
	// 9. 更新用户信息
	_, er := user_service.SetUserInfo(ctx, u.ID)
	if er != nil {
		return fmt.Errorf("用户信息更新失败")
	}
	return nil

}

// 交易关闭
func closeTradeInfo(ctx *gin.Context, mr ParamBaseReq) error {
	msg := tools.UrlDecode(mr.Msg)
	var msgInfo MsgInfoClose
	err := json.Unmarshal([]byte(msg), &msgInfo)
	if err != nil {
		return err
	}
	var bid = mr.Id
	trade, exists, _ := new(tables.YzTrade).GetTradeInfoByBid(bid)
	if !exists {
		return fmt.Errorf("该交易不存在")
	}
	// 该交易已经存在，无需进行更新
	trade.CloseReason = msgInfo.CloseReason
	trade.CloseType = msgInfo.CloseType
	trade.CloseTradeTime = msgInfo.UpdateTime
	err = new(tables.YzTrade).UpdateTrade(trade.ID, trade, "close_reason, close_type, create_trade_time") // 更新关闭消息
	if err != nil {
		return fmt.Errorf("该交易状态更新失败")
	}
	return nil
}

// 记录消息
func (*Bs) RecordMsg(ctx *gin.Context, mr ParamBaseReq) error {
	// 查询该交易单是否已经完成
	trade, exists, _ := new(tables.YzTrade).GetTradeInfoByBid(mr.Id)
	if exists && (trade.Status == tables.TradePaid || trade.Status == tables.TradeSuccess || trade.Status == tables.TradeClose) { // 该消息废弃
		return nil
	}
	// 1. 记录消息
	yzMsg := tables.YzMessage{
		MsgId:     mr.MsgId,
		Bid:       mr.Id,
		Mode:      mr.Mode,
		ClientId:  mr.ClientId,
		Version:   mr.Version,
		SendCount: mr.SendCount,
		Type:      mr.Type,
		Sign:      mr.Sign,
		Status:    mr.Status,
		RootKdtId: mr.RootKdtId,
		KdtId:     mr.KdtId,
		KdtName:   mr.KdtName,
		MsgInfo:   tools.UrlDecode(mr.Msg),
	}
	variable.DB.MySQL.Create(&yzMsg) // 错误失败都无关系,仅做记录
	return nil
}

// 消息回调
func (b *Bs) YzMessageCall(ctx *gin.Context, mr ParamBaseReq) error {
	// 1. 记录消息
	b.RecordMsg(ctx, mr)

	// 2. 校验sign
	err := new(YzBase).VerificationSign(mr.Sign, mr.Msg)
	if err != nil {
		return err
	}

	var eventType = mr.Type
	switch eventType {
	case "trade_TradeCreate": // 交易创建
		createTradeInfo(ctx, mr)
	case "trade_TradePaid": // 交易支付
		err := successTradeInfo(ctx, mr) // 买家付款,会员卡生效
		if err != nil {
			return err
		}
	case "trade_TradeBuyerPay": // 买家付款成功,交易成功
	case "trade_TradeSuccess": // 交易成功
	case "trade_TradeClose": // 交易关闭
		closeTradeInfo(ctx, mr)
	case "trade_refund_RefundSellerAgree": // 卖家同意退款
	case "trade_refund_RefundSellerCreated": // 卖家主动退款
	default:
	}

	return nil
}

// 调用search
func (b *Bs) YzItemsSearch(ctx *gin.Context) (interface{}, error) {
	// 解密手机号码
	token, err := new(YzApi).GetAccessTokenApi(ctx)
	if err != nil {
		return "", err
	}
	data, err := new(YzApi).YzItemsSearch(ctx, token)
	if err != nil {
		return "", err
	}
	var sii SearchItemInfo
	dataByte, _ := json.Marshal(data)
	err = json.Unmarshal(dataByte, &sii)
	if err != nil || sii.Count == 0 {
		return struct{}{}, nil
	}
	var items = make([]ItemsInfo, 0)
	ii := sii.Items
	for _, v := range ii {
		if tools.Contains(v.GroupNames, "有时练习会员") {
			items = append(items, v)
		}
	}

	return items, nil
}
